﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;

namespace StarOSWatch
{
    public class UseSysInfoWatch
    {
        public class ServerStatus
        {
            /// <summary>
            /// 运行时间
            /// </summary>
            public string RunTime { get; set; }
            /// <summary>
            /// 当前时间
            /// </summary>

            public DateTime CurrentTime { get; set; } = DateTime.Now;

            /// <summary>
            /// 内存
            /// </summary>
            public long Memory { get; set; }

            /// <summary>
            /// CPU
            /// </summary>
            public double Cpu { get; set; }


            /// <summary>
            /// 总内存
            /// </summary>
            public double MemoryTotal { get; set; }

            /// <summary>
            /// 内存使用
            /// </summary>
            public double MemoryTotalUse { get; set; }

            /// <summary>
            /// CPU使用率
            /// </summary>
            public double CpuTotalUse { get; set; }

            /// <summary>
            /// 磁盘
            /// </summary>
            public List<OsDrive> Drives { get; set; }

            public string Tag { get; set; }
        }

        private MemoryMetricsClient memoryMetricsClient = new MemoryMetricsClient();

        private int mProcessorCount;

        private readonly Process mProcess;

        private readonly long _mCpuMaxTime;

        private long _mLastTime;

        private double _mLastTotalProcessorTime;

        private ServerStatus _mInfo = new ServerStatus();

        private long _mLastGetTime;

        private int _mGetStatus = 0;

        public UseSysInfoWatch()
        {
            mProcessorCount = Environment.ProcessorCount;
            _mLastTime = RunTimeWatch.GetRunTimeMilliseconds();
            _mCpuMaxTime = mProcessorCount * 1000;
            mProcess = Process.GetCurrentProcess();
            _mLastTotalProcessorTime = mProcess.TotalProcessorTime.Milliseconds;
        }

        public ServerStatus GetServerStatus()
        {
            if (RunTimeWatch.GetRunTimeMilliseconds() - _mLastGetTime > 1000 && Interlocked.CompareExchange(ref _mGetStatus, 1, 0) == 0)
            {
                _mLastGetTime = RunTimeWatch.GetRunTimeMilliseconds();
                ServerStatus serverStatus = new ServerStatus();
                TimeSpan timeSpan = DateTime.Now - RunTimeWatch.StartTime;
                serverStatus.RunTime = $"{(long)timeSpan.Days}:{(long)timeSpan.Hours}:{(long)timeSpan.Minutes}:{(long)timeSpan.Seconds}";
                long runTimeMilliseconds = RunTimeWatch.GetRunTimeMilliseconds();
                double num = (double)(runTimeMilliseconds - _mLastTime) / 1000.0;
                _mLastTime = runTimeMilliseconds;
                double totalMilliseconds = mProcess.TotalProcessorTime.TotalMilliseconds;
                long num2 = (long)(num * (double)_mCpuMaxTime);
                double num3 = totalMilliseconds - _mLastTotalProcessorTime;
                _mLastTotalProcessorTime = totalMilliseconds;
                serverStatus.Cpu = (double)(int)(num3 / (double)num2 * 10000.0) / 100.0;
                if (serverStatus.Cpu > 100.0)
                {
                    serverStatus.Cpu = 100.0;
                }

                if (serverStatus.Cpu < 0.0)
                {
                    serverStatus.Cpu = 0.0;
                }

                serverStatus.Memory = Environment.WorkingSet / 1024 / 1024;
                _mInfo = serverStatus;
                Interlocked.Exchange(ref _mGetStatus, 0);
            }

            MemoryMetrics metrics = memoryMetricsClient.GetMetrics();
            _mInfo.MemoryTotal = metrics.Total;
            _mInfo.MemoryTotalUse = metrics.Used;
            _mInfo.CpuTotalUse = GetCpuTotalUse();
            _mInfo.Drives = OsDrives.GetDrivesInfo();
            if (_mInfo.Cpu > _mInfo.CpuTotalUse)
            {
                _mInfo.CpuTotalUse = _mInfo.Cpu;
            }
            return _mInfo;
        }

        private double GetCpuTotalUse()
        {
            IEnumerable<Process> enumerable = from p in Process.GetProcesses()
                                              where p.ProcessName != "Idle"
                                              select p;
            int num = 200;
            double num2 = 0.0;
            double num3 = 0.0;
            foreach (Process item in enumerable)
            {
                try
                {
                    num2 += item.TotalProcessorTime.TotalMilliseconds;
                }
                catch
                {
                }
            }

            Task.Delay(num).Wait();
            foreach (Process item2 in enumerable)
            {
                try
                {
                    num3 += item2.TotalProcessorTime.TotalMilliseconds;
                }
                catch
                {
                }
            }

            double num4 = num3 - num2;
            double num5 = num4 / (double)(num * mProcessorCount) * 100.0;
            if (num5 > 100.0)
            {
                num5 = 100.0;
            }

            if (num5 < 0.0)
            {
                num5 = 0.0;
            }

            return num5;
        }
    }
}
